package com.dyna.core.exception;


import com.dyna.domain.resp.R;
import com.dyna.domain.resp.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author zhoucaiwang
 * @date 2023/8/15
 */
@Slf4j
@RestControllerAdvice
public class GlobalException{

    @ExceptionHandler(Exception.class)
    public R<?> globalError(Exception e) {
        log.error(e.getMessage(), e);
        return R.fail(ResultCode.FAILURE,e.toString());
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public R<?> propertyNotFoundException(MethodArgumentNotValidException e) {
        Map<String, String> map = new HashMap<>(10);
        e.getFieldErrors().forEach(fieldError -> map.put(fieldError.getField(), fieldError.getDefaultMessage()));
        log.error(e.getMessage(), e);
        return R.data(ResultCode.PARAM_MISS.getCode(), map, ResultCode.PARAM_MISS.getMessage());
    }

    @ExceptionHandler(CustomException.class)
    public R<Throwable> customException(CustomException e) {
        log.error(e.getMessage(), e);
        return R.fail(e.getResultCode(),e.getMessage());
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public R<Throwable> illegalArgException(IllegalArgumentException e) {
        log.error(e.getMessage(), e);
        return R.fail(ResultCode.PARAM_MISS,e.getMessage());
    }

    /**
     * 处理 ConstraintViolationException 异常
     * 主要用于处理 @Validated 验证失败的情况
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public R<?> handleConstraintViolationException(ConstraintViolationException ex) {
        Map<String, String> errors = new HashMap<>();

        Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            // 简单直接的方式：只取属性路径的最后一部分作为字段名
            String propertyPath = violation.getPropertyPath().toString();
            String fieldName = propertyPath.contains(".")  ?
                    propertyPath.substring(propertyPath.lastIndexOf(".")  + 1) : propertyPath;
            // 如果是集合形式，去掉索引部分
            if (fieldName.contains("["))  {
                fieldName = fieldName.substring(0,  fieldName.indexOf("["));
            }

            String errorMessage = violation.getMessage();
            errors.put(fieldName,  errorMessage);
        }
        return R.data(ResultCode.PARAM_MISS.getCode(),  errors, ResultCode.PARAM_MISS.getMessage());
    }

}
